import pandas as pd
import re
import numpy as np

class DataProcessor:
    def __init__(self):
        return
    def normalize_date(self, date_str):
        """统一日期格式为YYYYMMDD字符串"""
        if pd.isna(date_str):
            return ""
        
        try:
            # 处理数值型日期（如20220101）
            if isinstance(date_str, (int, float)):
                date_str = str(int(date_str))
            
            if isinstance(date_str, str):
                # 清理特殊字符但保留斜杠
                date_str = re.sub(r'[^0-9/]', '', date_str)
                
                # 处理YYYY/M/D格式
                if re.match(r'^\d{4}/\d{1,2}/\d{1,2}$', date_str):
                    parts = date_str.split('/')
                    return f"{parts[0]}{parts[1].zfill(2)}{parts[2].zfill(2)}"
                
                # 移除非数字字符
                date_str = re.sub(r'[^0-9]', '', date_str)
                
                # 处理不同长度的日期
                if len(date_str) == 8:  # YYYYMMDD
                    return date_str
                elif len(date_str) == 6:  # YYYYMM
                    return date_str + "01"
                elif len(date_str) == 4:  # YYYY
                    return date_str + "0101"
            
            # 尝试通用日期解析
            parsed_date = pd.to_datetime(date_str, errors='coerce', format='mixed')
            if not pd.isna(parsed_date):
                return parsed_date.strftime('%Y%m%d')
            return ""
        except Exception as e:
            print(f"日期解析错误: {str(e)}")
            return ""

    def debug_show_data_info(self, df, name):
        """显示数据框关键信息（调试用）"""
        if df.empty:
            return f"{name}数据为空"
        
        info_lines = [
            f"{name}数据信息:",
            f"行数: {len(df)}",
            f"日期范围: {df['日期'].min()} 至 {df['日期'].max()}" if '日期' in df.columns else "无日期列",
            f"列: {', '.join(df.columns)}",
            "前3行:",
            df.head(3).to_string()
        ]
        return "\n".join(info_lines)

    def validate_data(self, df, expected_columns):
        """验证数据框是否包含必需列"""
        missing = [col for col in expected_columns if col not in df.columns]
        if missing:
            raise ValueError(f"数据验证失败，缺少必需列: {', '.join(missing)}")
        return 
    
    def calculate_probabilities(self, df, contract_type, lag_days):
        """计算净空单增减情况下指数增减的概率和平均涨幅（百分比）以及平均变化量（数值）"""
        stats = {}
        
        # 净空单变化量分类
        net_short_up = df[df['净空单变化量'] > 0]
        net_short_down = df[df['净空单变化量'] < 0]
        
        # 指数变化量分类
        index_up = df[df['指数变化量'] > 0]
        index_down = df[df['指数变化量'] < 0]
        
        # 计算各种组合
        both_up = df[(df['净空单变化量'] > 0) & (df['指数变化量'] > 0)]
        both_down = df[(df['净空单变化量'] < 0) & (df['指数变化量'] < 0)]
        net_short_up_index_down = df[(df['净空单变化量'] > 0) & (df['指数变化量'] < 0)]
        net_short_down_index_up = df[(df['净空单变化量'] < 0) & (df['指数变化量'] > 0)]
        
        # 计算概率
        total = len(df)
        if total > 0:
            stats['总样本数'] = total
            stats['净空单增加次数'] = len(net_short_up)
            stats['净空单减少次数'] = len(net_short_down)
            stats['指数增加次数'] = len(index_up)
            stats['指数减少次数'] = len(index_down)
            
            # 条件概率
            if len(net_short_up) > 0:
                stats['看跌概率'] = len(net_short_up_index_down) / len(net_short_up)  # 指数减少 | 净空单增加
                # 计算平均涨幅（百分比）- 使用指数变化百分比
                stats['净空单增加平均涨幅'] = net_short_up['指数变化百分比'].mean()
                # 计算平均变化量（数值）- 使用指数变化量
                stats['净空单增加平均变化量'] = net_short_up['指数变化量'].mean()
            else:
                stats['看跌概率'] = np.nan
                stats['净空单增加平均涨幅'] = np.nan
                stats['净空单增加平均变化量'] = np.nan
                
            if len(net_short_down) > 0:
                stats['看涨概率'] = len(net_short_down_index_up) / len(net_short_down)  # 指数增加 | 净空单减少
                # 计算平均涨幅（百分比）- 使用指数变化百分比
                stats['净空单减少平均涨幅'] = net_short_down['指数变化百分比'].mean()
                # 计算平均变化量（数值）- 使用指数变化量
                stats['净空单减少平均变化量'] = net_short_down['指数变化量'].mean()
            else:
                stats['看涨概率'] = np.nan
                stats['净空单减少平均涨幅'] = np.nan
                stats['净空单减少平均变化量'] = np.nan
        
        return stats
    
    def calculate_delayed_probabilities(self, df, contract_type, max_lag):
        """计算补涨/补跌的条件概率（从滞后第2天开始计算）"""
        results = []
        
        # 净空单增加的样本（用于补跌计算）
        net_short_up = df[df['净空单变化量'] > 0]
        
        # 净空单减少的样本（用于补涨计算）
        net_short_down = df[df['净空单变化量'] < 0]
        
        # 创建副本用于延迟计算
        df_up = net_short_up.copy()
        df_down = net_short_down.copy()
        
        # 计算延迟下跌概率（补跌）
        for k in range(2, max_lag + 1):  # 从滞后第2天开始计算
            # 创建延迟列
            for i in range(1, k + 1):
                df_up[f'指数变化量_延迟{i}天'] = df_up['指数变化量'].shift(-i)
                df_up[f'指数变化百分比_延迟{i}天'] = df_up['指数变化百分比'].shift(-i)
            
            # 条件1：前k-1天没有下跌（>=0）
            no_drop_conditions = []
            for i in range(1, k):
                no_drop_conditions.append(df_up[f'指数变化量_延迟{i}天'] >= 0)
            
            # 条件2：第k天下跌（<0）
            drop_condition = df_up[f'指数变化量_延迟{k}天'] < 0
            
            # 组合条件
            if no_drop_conditions:
                no_drop_condition = np.logical_and.reduce(no_drop_conditions)
                condition = no_drop_condition & drop_condition
            else:
                condition = drop_condition
            
            # 符合条件的样本数
            delayed_count = condition.sum()
            
            # 分母是前k-1天没有下跌的样本数
            total_count = no_drop_condition.sum() if no_drop_conditions else len(df_up)
            
            # 计算概率
            if total_count > 0:
                delayed_prob = delayed_count / total_count
                # 计算平均跌幅（百分比）
                avg_drop_pct = df_up[condition][f'指数变化百分比_延迟{k}天'].mean()
            else:
                delayed_prob = np.nan
                avg_drop_pct = np.nan
            
            # 保存结果
            results.append({
                '合约': contract_type,
                '类型': '补跌',
                '延迟天数': k,
                '概率': delayed_prob,
                '平均涨幅': avg_drop_pct,
                '满足条件样本数': delayed_count,
                '总样本数': total_count,
                '条件描述': f"T+1~T+{k-1}天未下跌, T+{k}天下跌"
            })
        
        # 计算延迟上涨概率（补涨）
        for k in range(2, max_lag + 1):  # 从滞后第2天开始计算
            # 创建延迟列
            for i in range(1, k + 1):
                df_down[f'指数变化量_延迟{i}天'] = df_down['指数变化量'].shift(-i)
                df_down[f'指数变化百分比_延迟{i}天'] = df_down['指数变化百分比'].shift(-i)
            
            # 条件1：前k-1天没有上涨（<=0）
            no_rise_conditions = []
            for i in range(1, k):
                no_rise_conditions.append(df_down[f'指数变化量_延迟{i}天'] <= 0)
            
            # 条件2：第k天上涨（>0）
            rise_condition = df_down[f'指数变化量_延迟{k}天'] > 0
            
            # 组合条件
            if no_rise_conditions:
                no_rise_condition = np.logical_and.reduce(no_rise_conditions)
                condition = no_rise_condition & rise_condition
            else:
                condition = rise_condition
            
            # 符合条件的样本数
            delayed_count = condition.sum()
            
            # 分母是前k-1天没有上涨的样本数
            total_count = no_rise_condition.sum() if no_rise_conditions else len(df_down)
            
            # 计算概率
            if total_count > 0:
                delayed_prob = delayed_count / total_count
                # 计算平均涨幅（百分比）
                avg_rise_pct = df_down[condition][f'指数变化百分比_延迟{k}天'].mean()
            else:
                delayed_prob = np.nan
                avg_rise_pct = np.nan
            
            # 保存结果
            results.append({
                '合约': contract_type,
                '类型': '补涨',
                '延迟天数': k,
                '概率': delayed_prob,
                '平均涨幅': avg_rise_pct,
                '满足条件样本数': delayed_count,
                '总样本数': total_count,
                '条件描述': f"T+1~T+{k-1}天未上涨, T+{k}天上涨"
            })
        
        return results
    
    def analyze_significant_change(self, df, contract_type, std_multiplier=1.0, max_lag=5, 
                            threshold_method="fixed", quantile=90.0, predict_days=[2, 3]):
        """分析净空单显著变化（增大或减小）对指数的影响，并返回结果和样本数据"""
        results = []
        samples = []  # 存储样本数据

        # 确保predictions变量存在
        predictions = []
        
        # 0. 参数校验 - 只允许单一方法
        if threshold_method not in ["fixed", "rolling", "quantile"]:
            threshold_method = "fixed"  # 默认固定阈值法
        
        # 1. 为整个数据集添加滞后列（T+1到T+max_lag天）
        for k in range(1, max_lag + 1):
            df[f'指数变化量_延迟{k}天'] = df['指数变化量'].shift(-k)
            df[f'指数变化百分比_延迟{k}天'] = df['指数变化百分比'].shift(-k)
        
        # 初始化阈值变量（用于预测）
        increase_threshold = np.nan
        decrease_threshold = np.nan
        increase_threshold_quantile = np.nan
        decrease_threshold_quantile = np.nan
        
        # 2. 分离正值（增加）和负值（减少）的变化量
        # 只考虑有实际变化的数据（排除变化量为0的情况）
        positive_changes = df[df['净空单变化量'] > 0].copy()
        negative_changes = df[df['净空单变化量'] < 0].copy()
        
        # 3. 方法1: 固定阈值法
        if threshold_method == "fixed":
            # 计算正值（增加）的变化量的均值和标准差
            if not positive_changes.empty:
                pos_mean = positive_changes['净空单变化量'].mean()
                pos_std = positive_changes['净空单变化量'].std()
                increase_threshold = pos_mean + std_multiplier * pos_std
                
                # 筛选显著增大的样本（只从正值变化中筛选）
                significant_increase = positive_changes[positive_changes['净空单变化量'] > increase_threshold].copy()
                
                # 分析显著增大（看跌）
                if not significant_increase.empty:
                    for k in range(1, max_lag + 1):
                        pct_col_name = f'指数变化百分比_延迟{k}天'
                        
                        # 计算平均变化量百分比（不区分涨跌）
                        avg_change_pct = significant_increase[pct_col_name].mean()
                        
                        # 计算下跌概率
                        drop_condition = significant_increase[f'指数变化量_延迟{k}天'] < 0
                        drop_count = drop_condition.sum()
                        total_count = len(significant_increase) - significant_increase[f'指数变化量_延迟{k}天'].isna().sum()
                        prob = drop_count / total_count if total_count > 0 else np.nan
                        
                        results.append({
                            '合约': contract_type,
                            '变化类型': '显著增大',
                            '方向': '正值',
                            '滞后天数': k,
                            '平均变化量百分比': avg_change_pct,
                            '概率': prob,  # 添加概率值
                            '满足条件样本数': total_count,
                            '变化描述': '下跌' if avg_change_pct < 0 else '上涨',
                            # 新增曲线数据点，用于插值预测
                            '曲线数据': [
                                {
                                    '阈值': increase_threshold,
                                    '概率': prob,
                                    '平均变化量百分比': avg_change_pct
                                }
                            ],
                            '方法': '固定阈值法',
                            '标准差倍数': std_multiplier,
                            '净空单均值': pos_mean,
                            '净空单标准差': pos_std,
                            '阈值': increase_threshold
                        })
                    
                    # 收集样本数据
                    sample_df = significant_increase.copy()
                    sample_df['变化类型'] = '显著增大'
                    sample_df['合约'] = contract_type
                    sample_df['方法'] = '固定阈值法'
                    sample_df['阈值'] = increase_threshold
                    samples.append(sample_df)
        
            # 计算负值（减少）的变化量的均值和标准差
            if not negative_changes.empty:
                neg_mean = negative_changes['净空单变化量'].mean()
                neg_std = negative_changes['净空单变化量'].std()
                decrease_threshold = neg_mean - std_multiplier * neg_std  # 注意这里是减法
                
                # 筛选显著减小的样本（只从负值变化中筛选）
                significant_decrease = negative_changes[negative_changes['净空单变化量'] < decrease_threshold].copy()
                
                # 分析显著减小（看涨）
                if not significant_decrease.empty:
                    for k in range(1, max_lag + 1):
                        pct_col_name = f'指数变化百分比_延迟{k}天'
                        
                        # 计算平均变化量百分比（不区分涨跌）
                        avg_change_pct = significant_decrease[pct_col_name].mean()
                        
                        # 计算上涨概率
                        rise_condition = significant_decrease[f'指数变化量_延迟{k}天'] > 0
                        rise_count = rise_condition.sum()
                        total_count = len(significant_decrease) - significant_decrease[f'指数变化量_延迟{k}天'].isna().sum()
                        prob = rise_count / total_count if total_count > 0 else np.nan
                        
                        results.append({
                            '合约': contract_type,
                            '变化类型': '显著减小',
                            '方向': '负值',
                            '滞后天数': k,
                            '平均变化量百分比': avg_change_pct,
                            '概率': prob,  # 添加概率值
                            '满足条件样本数': total_count,
                            '变化描述': '上涨' if avg_change_pct > 0 else '下跌',
                            # 新增曲线数据点，用于插值预测
                            '曲线数据': [
                                {
                                    '阈值': decrease_threshold,
                                    '概率': prob,
                                    '平均变化量百分比': avg_change_pct
                                }
                            ],
                            '方法': '固定阈值法',
                            '标准差倍数': std_multiplier,
                            '净空单均值': neg_mean,
                            '净空单标准差': neg_std,
                            '阈值': decrease_threshold
                        })
                    
                    # 收集样本数据
                    sample_df = significant_decrease.copy()
                    sample_df['变化类型'] = '显著减小'
                    sample_df['合约'] = contract_type
                    sample_df['方法'] = '固定阈值法'
                    sample_df['阈值'] = decrease_threshold
                    samples.append(sample_df)

        # 4. 方法2: 滚动阈值法
        elif threshold_method == "rolling":
            # 创建滚动窗口统计函数（正负值分开）
            def rolling_stats(series, window=20, min_periods=10):
                """计算滚动窗口的均值和标准差（正负值分开）"""
                # 正值滚动统计
                pos_series = series.copy()
                pos_series[pos_series <= 0] = np.nan  # 只保留正值
                pos_mean = pos_series.rolling(window=window, min_periods=min_periods).mean()
                pos_std = pos_series.rolling(window=window, min_periods=min_periods).std()
                
                # 负值滚动统计
                neg_series = series.copy()
                neg_series[neg_series >= 0] = np.nan  # 只保留负值
                neg_mean = neg_series.rolling(window=window, min_periods=min_periods).mean()
                neg_std = neg_series.rolling(window=window, min_periods=min_periods).std()
                
                return pos_mean, pos_std, neg_mean, neg_std
            
            # 计算滚动统计量（使用前一天的数据）
            # 注意: 使用shift(1)确保不包含当天数据
            df['rolling_pos_mean'], df['rolling_pos_std'], df['rolling_neg_mean'], df['rolling_neg_std'] = rolling_stats(
                df['净空单变化量'].shift(1), window=20, min_periods=10
            )
            
            # 删除前20行（无滚动数据）
            df_rolling = df.dropna(subset=['rolling_pos_mean', 'rolling_pos_std', 'rolling_neg_mean', 'rolling_neg_std']).copy()
            
            if not df_rolling.empty:
                # 计算动态阈值
                increase_threshold_rolling = df_rolling['rolling_pos_mean'] + std_multiplier * df_rolling['rolling_pos_std']
                decrease_threshold_rolling = df_rolling['rolling_neg_mean'] - std_multiplier * df_rolling['rolling_neg_std']
                
                # 获取最后一个数据点的阈值（用于预测）
                if not df_rolling.empty:
                    increase_threshold = increase_threshold_rolling.iloc[-1]
                    decrease_threshold = decrease_threshold_rolling.iloc[-1]
                
                # 筛选显著增大的样本（滚动阈值法，正值）
                significant_increase_rolling = df_rolling[
                    (df_rolling['净空单变化量'] > 0) &  # 必须是正值
                    (df_rolling['净空单变化量'] > increase_threshold_rolling)
                ].copy()
                
                # 筛选显著减小的样本（滚动阈值法，负值）
                significant_decrease_rolling = df_rolling[
                    (df_rolling['净空单变化量'] < 0) &  # 必须是负值
                    (df_rolling['净空单变化量'] < decrease_threshold_rolling)
                ].copy()
                # 分析显著增大（看跌）- 滚动阈值法
                if not significant_increase_rolling.empty:
                    for k in range(1, max_lag + 1):
                        pct_col_name = f'指数变化百分比_延迟{k}天'
                        
                        # 计算平均变化量百分比（不区分涨跌）
                        avg_change_pct = significant_increase_rolling[pct_col_name].mean()
                        
                        # 计算下跌概率
                        drop_condition = significant_increase_rolling[f'指数变化量_延迟{k}天'] < 0
                        drop_count = drop_condition.sum()
                        total_count = len(significant_increase_rolling) - significant_increase_rolling[f'指数变化量_延迟{k}天'].isna().sum()
                        prob = drop_count / total_count if total_count > 0 else np.nan
                        
                        # 计算平均滚动统计量
                        avg_rolling_pos_mean = significant_increase_rolling['rolling_pos_mean'].mean()
                        avg_rolling_pos_std = significant_increase_rolling['rolling_pos_std'].mean()
                        avg_threshold = significant_increase_rolling['rolling_pos_mean'] + std_multiplier * significant_increase_rolling['rolling_pos_std']
                        avg_threshold = avg_threshold.mean()
                        
                        results.append({
                            '合约': contract_type,
                            '变化类型': '显著增大',
                            '方向': '正值',
                            '滞后天数': k,
                            '平均变化量百分比': avg_change_pct,
                            '概率': prob,  # 添加概率值
                            '满足条件样本数': len(significant_increase_rolling),
                            '变化描述': '下跌' if avg_change_pct < 0 else '上涨',
                            '方法': '滚动阈值法',
                            '标准差倍数': std_multiplier,
                            '滚动窗口': 20,
                            '滚动均值': avg_rolling_pos_mean,
                            '滚动标准差': avg_rolling_pos_std,
                            '阈值': avg_threshold,
                            # 新增曲线数据点，用于插值预测
                            '曲线数据': [
                                {
                                    '阈值': avg_threshold,
                                    '概率': prob,
                                    '平均变化量百分比': avg_change_pct
                                }
                            ],
                        })
                    
                    # 收集样本数据
                    sample_df = significant_increase_rolling.copy()
                    sample_df['变化类型'] = '显著增大'
                    sample_df['合约'] = contract_type
                    sample_df['方法'] = '滚动阈值法'
                    sample_df['阈值'] = increase_threshold_rolling
                    samples.append(sample_df)
                    
                # 分析显著减小（看涨）- 滚动阈值法
                if not significant_decrease_rolling.empty:
                    for k in range(1, max_lag + 1):
                        pct_col_name = f'指数变化百分比_延迟{k}天'
                        
                        # 计算平均变化量百分比（不区分涨跌）
                        avg_change_pct = significant_decrease_rolling[pct_col_name].mean()
                        
                        # 计算上涨概率
                        rise_condition = significant_decrease_rolling[f'指数变化量_延迟{k}天'] > 0
                        rise_count = rise_condition.sum()
                        total_count = len(significant_decrease_rolling) - significant_decrease_rolling[f'指数变化量_延迟{k}天'].isna().sum()
                        prob = rise_count / total_count if total_count > 0 else np.nan
                        
                        # 计算平均滚动统计量
                        avg_rolling_neg_mean = significant_decrease_rolling['rolling_neg_mean'].mean()
                        avg_rolling_neg_std = significant_decrease_rolling['rolling_neg_std'].mean()
                        avg_threshold = significant_decrease_rolling['rolling_neg_mean'] - std_multiplier * significant_decrease_rolling['rolling_neg_std']
                        avg_threshold = avg_threshold.mean()
                        
                        results.append({
                            '合约': contract_type,
                            '变化类型': '显著减小',
                            '方向': '负值',
                            '滞后天数': k,
                            '平均变化量百分比': avg_change_pct,
                            '概率': prob,  # 添加概率值
                            '满足条件样本数': len(significant_decrease_rolling),
                            '变化描述': '上涨' if avg_change_pct > 0 else '下跌',
                            '方法': '滚动阈值法',
                            '标准差倍数': std_multiplier,
                            '滚动窗口': 20,
                            '滚动均值': avg_rolling_neg_mean,
                            '滚动标准差': avg_rolling_neg_std,
                            '阈值': avg_threshold,
                            # 新增曲线数据点，用于插值预测
                            '曲线数据': [
                                {
                                    '阈值': avg_threshold,
                                    '概率': prob,
                                    '平均变化量百分比': avg_change_pct
                                }
                            ],
                        })
                    
                    # 收集样本数据
                    sample_df = significant_decrease_rolling.copy()
                    sample_df['变化类型'] = '显著减小'
                    sample_df['合约'] = contract_type
                    sample_df['方法'] = '滚动阈值法'
                    sample_df['阈值'] = decrease_threshold_rolling
                    samples.append(sample_df)

        # 5. 方法3: 分位数阈值法
        elif threshold_method == "quantile":
            # 复制数据
            df_quantile = df.copy()
            
            # 分离正值和负值
            positive_changes = df_quantile[df_quantile['净空单变化量'] > 0]
            negative_changes = df_quantile[df_quantile['净空单变化量'] < 0]
            
            # 初始化变量，避免未定义错误
            significant_increase_quantile = pd.DataFrame()
            significant_decrease_quantile = pd.DataFrame()
            
            # 计算分位数阈值
            if not positive_changes.empty:
                # 正值变化量取上分位数（例如90%）
                increase_threshold_quantile = np.percentile(
                    positive_changes['净空单变化量'], quantile
                )
                # 筛选显著增大的样本（分位数阈值法，正值）
                significant_increase_quantile = positive_changes[
                    positive_changes['净空单变化量'] > increase_threshold_quantile
                ].copy()
            else:
                increase_threshold_quantile = np.nan
                    
            if not negative_changes.empty:
                # 负值变化量取下分位数（例如10%）
                decrease_threshold_quantile = np.percentile(
                    negative_changes['净空单变化量'], 100 - quantile
                )
                # 筛选显著减小的样本（分位数阈值法，负值）
                significant_decrease_quantile = negative_changes[
                    negative_changes['净空单变化量'] < decrease_threshold_quantile
                ].copy()
            else:
                decrease_threshold_quantile = np.nan
                    
            # 分析显著增大（看跌）- 分位数阈值法
            if not significant_increase_quantile.empty:
                for k in range(1, max_lag + 1):
                    pct_col_name = f'指数变化百分比_延迟{k}天'
                    
                    # 计算平均变化量百分比（不区分涨跌）
                    avg_change_pct = significant_increase_quantile[pct_col_name].mean()
                    
                    # 计算下跌概率
                    drop_condition = significant_increase_quantile[f'指数变化量_延迟{k}天'] < 0
                    drop_count = drop_condition.sum()
                    total_count = len(significant_increase_quantile) - significant_increase_quantile[f'指数变化量_延迟{k}天'].isna().sum()
                    prob = drop_count / total_count if total_count > 0 else np.nan
                    
                    results.append({
                        '合约': contract_type,
                        '变化类型': '显著增大',
                        '方向': '正值',
                        '滞后天数': k,
                        '平均变化量百分比': avg_change_pct,
                        '概率': prob,  # 添加概率值
                        '满足条件样本数': len(significant_increase_quantile),
                        '变化描述': '下跌' if avg_change_pct < 0 else '上涨',
                        '方法': '分位数阈值法',
                        '分位数': quantile,
                        '阈值': increase_threshold_quantile,
                        # 新增曲线数据点，用于插值预测
                        '曲线数据': [
                            {
                                '阈值': quantile,
                                '概率': prob,
                                '平均变化量百分比': avg_change_pct
                            }
                        ],
                    })
                
                # 收集样本数据
                sample_df = significant_increase_quantile.copy()
                sample_df['变化类型'] = '显著增大'
                sample_df['合约'] = contract_type
                sample_df['方法'] = '分位数阈值法'
                sample_df['阈值'] = increase_threshold_quantile
                samples.append(sample_df)
                    
            # 分析显著减小（看涨）- 分位数阈值法
            if not significant_decrease_quantile.empty:
                for k in range(1, max_lag + 1):
                    pct_col_name = f'指数变化百分比_延迟{k}天'
                    
                    # 计算平均变化量百分比（不区分涨跌）
                    avg_change_pct = significant_decrease_quantile[pct_col_name].mean()
                    
                    # 计算上涨概率
                    rise_condition = significant_decrease_quantile[f'指数变化量_延迟{k}天'] > 0
                    rise_count = rise_condition.sum()
                    total_count = len(significant_decrease_quantile) - significant_decrease_quantile[f'指数变化量_延迟{k}天'].isna().sum()
                    prob = rise_count / total_count if total_count > 0 else np.nan
                    
                    results.append({
                        '合约': contract_type,
                        '变化类型': '显著减小',
                        '方向': '负值',
                        '滞后天数': k,
                        '平均变化量百分比': avg_change_pct,
                        '概率': prob,  # 添加概率值
                        '满足条件样本数': len(significant_decrease_quantile),
                        '变化描述': '上涨' if avg_change_pct > 0 else '下跌',
                        '方法': '分位数阈值法',
                        '分位数': quantile,
                        '阈值': decrease_threshold_quantile,
                        # 新增曲线数据点，用于插值预测
                        '曲线数据': [
                            {
                                '阈值': quantile,
                                '概率': prob,
                                '平均变化量百分比': avg_change_pct
                            }
                        ],
                    })
                
                # 收集样本数据
                sample_df = significant_decrease_quantile.copy()
                sample_df['变化类型'] = '显著减小'
                sample_df['合约'] = contract_type
                sample_df['方法'] = '分位数阈值法'
                sample_df['阈值'] = decrease_threshold_quantile
                samples.append(sample_df)
        
        # ===== 新增预测功能 =====
        predictions = []
        
        # 使用插值法进行预测
        if not df.empty and results:
            try:
                # 获取最后一个净空单变化量
                last_net_short_change = df.iloc[-1]['净空单变化量']
                last_date = df.iloc[-1]['日期']
                
                # 对于需要预测的天数
                for lag in predict_days:
                    # 只预测T+2和T+3
                    if lag not in [2, 3]:
                        continue
                        
                    # 查找对应滞后天数的统计结果
                    for stat in results:
                        if stat['滞后天数'] != lag:
                            continue
                            
                        # 确定变化类型
                        if last_net_short_change > 0:  # 净空单增加
                            change_type = '显著增大'
                        else:  # 净空单减少
                            change_type = '显著减小'
                            
                        if stat['变化类型'] != change_type:
                            continue
                            
                        # 检查是否有曲线数据
                        if '曲线数据' not in stat or len(stat['曲线数据']) < 2:
                            # 没有足够数据点，使用原始统计值
                            predictions.append({
                                '合约': contract_type,
                                '预测日期': last_date,
                                '预测滞后天数': lag,
                                '净空单变化量': last_net_short_change,
                                '预测类型': stat['变化类型'],
                                '预测概率': stat['概率'],
                                '预测平均涨幅': stat['平均变化量百分比'],
                                '阈值': stat.get('阈值', np.nan),
                                '阈值方法': stat['方法'],
                                '是否满足阈值': "是",
                                '预测方法': '直接使用统计值',
                                '预测日期类型': f"D+{lag-1}"  # 预测的是未来第几天
                            })
                            continue
                            
                        # 获取曲线数据点
                        curve_data = stat['曲线数据']
                        thresholds = [d['阈值'] for d in curve_data]
                        probabilities = [d['概率'] for d in curve_data]
                        avg_changes = [d['平均变化量百分比'] for d in curve_data]
                        
                        # 使用线性插值计算预测概率
                        pred_prob = np.interp(
                            last_net_short_change, 
                            thresholds, 
                            probabilities
                        )
                        
                        # 使用线性插值计算预测平均涨幅
                        pred_avg_change = np.interp(
                            last_net_short_change, 
                            thresholds, 
                            avg_changes
                        )
                        
                        # 保存插值预测结果
                        predictions.append({
                            '合约': contract_type,
                            '预测日期': last_date,
                            '预测滞后天数': lag,
                            '净空单变化量': last_net_short_change,
                            '预测类型': stat['变化类型'],
                            '预测概率': pred_prob,
                            '预测平均涨幅': pred_avg_change,
                            '阈值': thresholds,
                            '阈值方法': stat['方法'],
                            '是否满足阈值': "是",
                            '预测方法': '线性插值',
                            '预测日期类型': f"D+{lag-1}"  # 预测的是未来第几天
                        })
            except Exception as e:
                print(f"预测时出错: {str(e)}")             

        # 保存预测结果
        self.predictions.extend(predictions)
        
        return results, samples, predictions
    
    def read_file(self, path):
        """统一文件读取方式，支持多种格式和编码"""
        if path.endswith(('.xlsx', '.xls')):
            return pd.read_excel(path)
        else:  # 默认按CSV处理
            # 尝试不同编码
            encodings = ['utf-8', 'gbk', 'latin1']
            for enc in encodings:
                try:
                    return pd.read_csv(path, encoding=enc)
                except:
                    continue
            # 如果所有编码都失败，使用错误替换策略
            return pd.read_csv(path, encoding='utf-8', errors='replace')